package com.gaowl.gulimall.product.service.impl;

import com.gaowl.common.constant.ProductConstant;
import com.gaowl.gulimall.product.dao.AttrAttrgroupRelationDao;
import com.gaowl.gulimall.product.dao.AttrGroupDao;
import com.gaowl.gulimall.product.dao.CategoryDao;
import com.gaowl.gulimall.product.entity.AttrAttrgroupRelationEntity;
import com.gaowl.gulimall.product.entity.AttrGroupEntity;
import com.gaowl.gulimall.product.entity.CategoryEntity;
import com.gaowl.gulimall.product.service.CategoryService;
import com.gaowl.gulimall.product.vo.AttrGroupRelationVo;
import com.gaowl.gulimall.product.vo.AttrResponseVo;
import com.gaowl.gulimall.product.vo.AttrVo;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gaowl.common.utils.PageUtils;
import com.gaowl.common.utils.Query;

import com.gaowl.gulimall.product.dao.AttrDao;
import com.gaowl.gulimall.product.entity.AttrEntity;
import com.gaowl.gulimall.product.service.AttrService;
import org.springframework.transaction.annotation.Transactional;


@Service("attrService")
public class AttrServiceImpl extends ServiceImpl<AttrDao, AttrEntity> implements AttrService {

    @Autowired
    AttrAttrgroupRelationDao attrAttrgroupRelationDao;

    @Autowired
    CategoryDao categoryDao;

    @Autowired
    AttrGroupDao attrGroupDao;

    @Autowired
    CategoryService categoryService;

    @Autowired
    AttrDao attrDao;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<AttrEntity> page = this.page(
                new Query<AttrEntity>().getPage(params),
                new QueryWrapper<>()
        );

        return new PageUtils(page);
    }


    /**
     * 获取分类规格参数
     * @param params 分页参数
     * @param catelogId 三级分类的类别id
     */
    @Override
    public PageUtils queryBaseAttrPage(Map<String, Object> params, Long catelogId, String attrType) {
        QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("attr_type", "base".equalsIgnoreCase(attrType)?
                ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode():ProductConstant.AttrEnum.ATTR_TYPE_SALE.getCode());

        if (catelogId != 0){  // 类别id为0时，查询所有规格参数；不为0时根据相应参数进行模糊查询
            queryWrapper.eq("catelog_id", catelogId);
        }
        String key = (String) params.get("key");
        if (!StringUtils.isEmpty(key)){
            // (attr_id = ? or attr_name like %?%)
            queryWrapper.and((wrapper)->{
                wrapper.eq("attr_id", key).or().like("attr_name", key);
            });
        }

        IPage<AttrEntity> page = this.page(new Query<AttrEntity>().getPage(params), queryWrapper);
        PageUtils pageUtils = new PageUtils(page);   // 此时的pageUtils对象中缺乏分类名称和属性分组名称等信息！

        // 大表尽量不要进行联表查询，会产生大量中间数据，且时间较慢！！
        // 可先生成中间结果，然后基于中间结果再次查询
        List<AttrEntity> records = page.getRecords();
        List<AttrResponseVo> attrResponseVoList = records.stream().map((attrEntity) -> {
            AttrResponseVo attrResponseVo = new AttrResponseVo();
            BeanUtils.copyProperties(attrEntity, attrResponseVo);
            // 1.设置分类名称
            CategoryEntity categoryEntity = categoryDao.selectById(attrEntity.getCatelogId());
            if (categoryEntity != null) {
                attrResponseVo.setCatelogName(categoryEntity.getName());
            }

            // 2.设置属性分组名称
            // 2.1 根据属性id拿到关系表对象  2.2 从关系表对象中取出属性分组id  2.3 根据属性分组id拿到属性分组对象
            Long attrId = attrEntity.getAttrId();
            if (attrId != null){
                AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = attrAttrgroupRelationDao.selectOne(
                        new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrId));
                if (attrAttrgroupRelationEntity != null){  // 存在对应的关系表对象
                    //System.out.println(attrAttrgroupRelationEntity.toString());
                    Long attrGroupId = attrAttrgroupRelationEntity.getAttrGroupId();
                    if (attrGroupId != null){
                        AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(attrGroupId);
                        if (attrGroupEntity != null) {   // 存在对应的属性分组对象
                            attrResponseVo.setGroupName(attrGroupEntity.getAttrGroupName());
                        }
                    }
                }
            }
            return attrResponseVo;
        }).collect(Collectors.toList());

        pageUtils.setList(attrResponseVoList);
        return pageUtils;
    }

    /**
     * 查询 属性 的详细信息（包含分组id、分类路径）
     */
    @Override
    public AttrResponseVo getDetailedInfoById(Long attrId) {

        AttrEntity attrEntity = this.getById(attrId);

        // 拷贝基本参数
        AttrResponseVo attrResponseVo = new AttrResponseVo();
        BeanUtils.copyProperties(attrEntity, attrResponseVo);

        // 只有基本属性时，才设置分组信息；销售属性无需设置
        if (attrEntity.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()){
            AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = attrAttrgroupRelationDao.selectOne(
                    new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrId));
            if (attrAttrgroupRelationEntity != null) {  // 存在属性分组关系对象
                attrResponseVo.setAttrGroupId(attrAttrgroupRelationEntity.getAttrGroupId());  // 分组id
            }
        }

        // 设置分类路径
        Long catelogId = attrEntity.getCatelogId();
        Long[] catelogPathById = categoryService.findCatelogPathById(catelogId);
        attrResponseVo.setCatelogPath(catelogPathById);  // 三级分类路径

        return attrResponseVo;
    }

    /**
     * 保存前端传过来的AttrVo（相比于AttrEntity,其还保存了AttrGroupId信息）
     *      1.保存在attr表在保存基本的attr信息
     *      2.在属性分组表中保存关联信息
     *
     * @param attrVo 属性视图对象
     */
    @Transactional  // 开始事务
    @Override
    public void saveAttrVo(AttrVo attrVo) {
        AttrEntity attrEntity = new AttrEntity();
        // 利用spring提供的工具类进行属性复制，要求对应的属性名是一致的
        BeanUtils.copyProperties(attrVo, attrEntity);
        this.save(attrEntity);   // 保存在attr表在保存基本的attr信息

        // 保存关联关系
        if (attrVo.getAttrGroupId() != null) {
            AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
            relationEntity.setAttrGroupId(attrVo.getAttrGroupId());
            relationEntity.setAttrId(attrEntity.getAttrId());  // attrVo无有效的attrId信息！！！！！
            attrAttrgroupRelationDao.insert(relationEntity);
        }
    }

    @Transactional
    @Override
    public void updateAttrVo(AttrVo attrVo) {
        AttrEntity attrEntity = new AttrEntity();
        // 利用spring提供的工具类进行属性复制，要求对应的属性名是一致的
        BeanUtils.copyProperties(attrVo, attrEntity);
        this.updateById(attrEntity);  // 更新基本的商品属性

        // 仅基本属性需要『更新或新增 分组关联』，销售属性无需进行分组相关操作
        if (attrVo.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()){
            AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = new AttrAttrgroupRelationEntity();
            attrAttrgroupRelationEntity.setAttrId(attrVo.getAttrId());
            attrAttrgroupRelationEntity.setAttrGroupId(attrVo.getAttrGroupId());

            QueryWrapper<AttrAttrgroupRelationEntity> wrapper = new QueryWrapper<AttrAttrgroupRelationEntity>()
                    .eq("attr_id", attrVo.getAttrId());

            if (attrAttrgroupRelationDao.selectCount(wrapper) > 0) {  // 原先商品属性存在分组信息，执行更新操作
                attrAttrgroupRelationDao.update(attrAttrgroupRelationEntity, wrapper);
            }else {   // 原先商品属性不存在分组信息，执行新增操作
                attrAttrgroupRelationDao.insert(attrAttrgroupRelationEntity);
            }
        }
    }

    /**
     * 根据分组id，获取此分组关联的所有属性
     * @param attrGroupId 某个属性分组的id
     * @return 属性和分组间的关联关系
     */
    @Override
    public List<AttrEntity> getRelationAttr(Long attrGroupId) {
        // 1.先在关系表中根据分组id找到所有相关的属性id
        List<AttrAttrgroupRelationEntity> attrAttrgroupRelationEntities = attrAttrgroupRelationDao.selectList(
                new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_group_id", attrGroupId));
        List<Long> attrIdList = attrAttrgroupRelationEntities.stream().map((entity) -> {
            return entity.getAttrId();
        }).collect(Collectors.toList());

        // 2.根据属性id，在属性表中，取得所有的属性对象
        List<AttrEntity> attrEntityList= new ArrayList<>();
        if (attrIdList.size() > 0){  // 校验列表非空，避免SQL因为空元素出错
            attrEntityList = (List<AttrEntity>) this.listByIds(attrIdList);
        }
        return attrEntityList;
    }


    /**
     * 根据分组id，获取此分组没有关联的 本分类里面的其他基本属性
     * @param attrGroupId 某个属性分组的id
     * @param params 分页参数及模糊查询字段
     * @return 属性和分组间的关联关系
     */
    @Override
    public PageUtils getNoRelationAttr(Long attrGroupId, Map<String, Object> params) {
        // 当前分组只能关联自己所属的类别里面的属性，且此属性未被其他分组所关联

        // 1.本分组所属的类别
        Long catelogId = attrGroupDao.selectById(attrGroupId).getCatelogId();
        // 基础查询条件
        QueryWrapper<AttrEntity> unUsedAttrEntityQueryWrapper = new QueryWrapper<AttrEntity>()
                .eq("catelog_id", catelogId);

        // 2.该类别下 已被关联的属性
        // 2.1 该类别下的所有分组
        List<AttrGroupEntity> otherAttrGroupEntities = attrGroupDao.selectList(new QueryWrapper<AttrGroupEntity>()
                .eq("catelog_id", catelogId)); //.ne("attr_group_id", attrGroupId));
        List<Long> otherAttrGroupIds = otherAttrGroupEntities.stream()
                .map(AttrGroupEntity::getAttrGroupId).collect(Collectors.toList());

        // 2.1.这些分组已所包含的属性
        if (otherAttrGroupIds.size() > 0) {   // 非空校验
            List<AttrAttrgroupRelationEntity> relationEntities = attrAttrgroupRelationDao.selectList(
                    new QueryWrapper<AttrAttrgroupRelationEntity>().in("attr_group_id", otherAttrGroupIds));
            List<Long> usedAttrIdList = relationEntities.stream().map(AttrAttrgroupRelationEntity::getAttrId)
                    .collect(Collectors.toList());  // 该类别下 所有 已被关联的 属性

            // 3.该类别下 所有 未被关联的 属性
            if (usedAttrIdList.size() > 0) {   // 非空校验
                unUsedAttrEntityQueryWrapper.notIn("attr_id", usedAttrIdList);
            }
        }

        // 4. 构造模糊查询条件
        String key = (String) params.get("key");
        if (!StringUtils.isEmpty(key)){
            // (attr_id = ? or attr_name like %?%)
            unUsedAttrEntityQueryWrapper.and((wrapper)->{
                wrapper.eq("attr_id", key).or().like("attr_name", key);
            });
        }

        // 5.进行最终的分页查询
        IPage<AttrEntity> page = this.page(new Query<AttrEntity>().getPage(params), unUsedAttrEntityQueryWrapper);
        return new PageUtils(page);
    }


    /**
     * 删除属性与分组的关联关系
     * @param attrGroupRelationVos 包含属性id和分组id的关联关系对象列表
     */
    @Override
    public void deleteRelation(AttrGroupRelationVo[] attrGroupRelationVos) {
        List<AttrAttrgroupRelationEntity> entities = Arrays.asList(attrGroupRelationVos).stream()
            .map((attrGroupRelationVo) -> {
                AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = new AttrAttrgroupRelationEntity();
                BeanUtils.copyProperties(attrGroupRelationVo, attrAttrgroupRelationEntity);
                return attrAttrgroupRelationEntity;
            }).collect(Collectors.toList());

        attrAttrgroupRelationDao.deleteBatchRelation(entities);
    }


    /**
     * 新增属性与分组的关联关系
     * @param attrGroupRelationVos 包含属性id和分组id的关联关系对象列表
     */
    @Override
    public void addRelation(AttrGroupRelationVo[] attrGroupRelationVos) {
        for (AttrGroupRelationVo attrGroupRelationVo : attrGroupRelationVos) {
            AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = new AttrAttrgroupRelationEntity();
            BeanUtils.copyProperties(attrGroupRelationVo, attrAttrgroupRelationEntity);


            Integer selectCount = attrAttrgroupRelationDao.selectCount(new QueryWrapper<AttrAttrgroupRelationEntity>()
                    .eq("attr_id", attrGroupRelationVo.getAttrId()));
            if (selectCount == 0){  // 此属性未与其他分组关联时，方可进行关联操作
                attrAttrgroupRelationDao.insert(attrAttrgroupRelationEntity);
            }
        }
    }
}